#pragma once
#include "../protocol.hpp"
#include "../Log.hpp"

class UdpSocket{
  public:
    UdpSocket():socket_fd(-1){}

    void Init(){
      myaddr.sin_family = AF_INET;
      inet_aton(svr_ip, &myaddr.sin_addr);
      myaddr.sin_port = htons(svr_port);
    }

    bool Create(){
      socket_fd = socket(AF_INET, SOCK_DGRAM, 0);
      if(Perror(socket_fd, "socket", FATAL)){
        LOG("");
        return false;
      }
      return true;
    }

    bool Bind(){
      int ret =  bind(socket_fd, (sockaddr*)&myaddr, sizeof_sockaddr_in);
      if(Perror(ret, "bind", FATAL)){
        LOG("");
        return false;
      }
      return true;
    }

    int Recv(std::string& buf, sockaddr_in& src_addr = myaddr){
      buf.clear();
      char tmp[MAX_BUF_SIZE] = {0};
      socklen_t len = sizeof_sockaddr_in;
      int recv_size = recvfrom(socket_fd, tmp, MAX_BUF_SIZE - 1, 0, (sockaddr*)&src_addr, &len);
      if(Perror(recv_size, "recvfrom", WARING)){
        LOG("");
      }
      else if(recv_size == 0){
        printf("connect has been closed\n");
      }
      else{
        buf.assign(tmp, recv_size);
      }
      return recv_size;
    }

    int Send(const std::string& buf, const sockaddr_in& dest_addr = myaddr){
      int send_size = sendto(socket_fd, buf.data(), buf.size(), 0, (sockaddr*)&dest_addr, sizeof_sockaddr_in);
      if(Perror(send_size, "sendto", ERROR)){
        LOG("");
      }
      if(send_size == 0){
        printf("This socket has been closed\n");
      }
      return send_size;
    }

    void Close(){
      close(socket_fd);
      socket_fd = -1;
    }
  private:
    static sockaddr_in myaddr;
    int socket_fd;
};

sockaddr_in UdpSocket::myaddr;
